#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QModbusTcpClient>
#include <GlobalVar.h>
using namespace GlobalVar;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , m_modbusDevice(new QModbusRtuSerialMaster(this))
{
    ui->setupUi(this);
    _ChartUiInit();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_actionSetModbus_triggered()
{
    m_setModbusDialog.show();
}

void MainWindow::on_actionSetSerial_triggered()
{
    m_setSerialDialog.show();
}

void MainWindow::on_pushButton_start_released()
{
    if(!m_modbusDevice){
        _ModbusConnect();
        m_modbusRequests();
    }

    if(QModbusDevice::State::ConnectedState == m_modbusDevice->state()){
        m_modbusDevice->disconnectDevice();
        ui->pushButton_start->setStyleSheet("background-color:red");
    }
    else
    {
        _ModbusConnect();
        m_modbusRequests();
    }

}

void MainWindow::_ChartUiInit()
{
    u_chart.reset(new QChart());
    u_chart->setTitle("Chart");
    u_chart->createDefaultAxes();
    u_chart->setAnimationOptions(QChart::SeriesAnimations);

    u_chartView = new QChartView(u_chart.get(), this);
    u_chartView->setRenderHint(QPainter::Antialiasing);
    ui->verticalLayout->addWidget(u_chartView);

    u_axisX = new QValueAxis(this);
    u_axisX->setRange(0,10);
    u_axisX->setTitleText("X");
    u_axisX->setTickCount(10);
    u_axisY = new QValueAxis(this);
    u_axisY->setRange(0,10);
    u_axisY->setTitleText("Y");
    u_axisY->setTickCount(10);
    u_chart->addAxis(u_axisY, Qt::AlignmentFlag::AlignLeft);
    u_chart->addAxis(u_axisX, Qt::AlignmentFlag::AlignBottom);


    u_lineSeries = new QLineSeries(this);
    u_lineSeries->setPen( QPen(Qt::blue, 1, Qt::SolidLine) );
    u_lineSeries->setName("Modbus Data");
    u_lineSeries->setColor(Qt::blue);
    u_lineSeries->setPointLabelsVisible(true);//点的数据提示标签
    u_lineSeries->setPointLabelsColor(Qt::red); //点的数据提示标签颜色
    u_lineSeries->setPointsVisible(true); //数据点
    u_lineSeries->setPointLabelsFormat("(@yPoint)");
    u_chart->addSeries(u_lineSeries);//必须在线连续之前绑定，否则在显示时坐标轴不变
    u_lineSeries->attachAxis(u_axisX);
    u_lineSeries->attachAxis(u_axisY);
}

void MainWindow::_ModbusConnect()
{
    /* set param */
    if(SerialSettings::ConnectionEnum::Serial == g_serialSetting.connectType){
        if(m_modbusDevice == nullptr){
            m_modbusDevice = new QModbusRtuSerialMaster(this);
        } else {
            QModbusRtuSerialMaster* temp =dynamic_cast<QModbusRtuSerialMaster*>(m_modbusDevice);
            if(temp == nullptr){
                delete m_modbusDevice;
                m_modbusDevice = new QModbusRtuSerialMaster(this);
            }
        }

        m_modbusDevice = new QModbusRtuSerialMaster(this);
        m_modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,g_serialSetting.portName);
        m_modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, g_serialSetting.parity);
        m_modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, g_serialSetting.baud);
        m_modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, g_serialSetting.dataBits);
        m_modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, g_serialSetting.stopBits);
    } else {
        if(m_modbusDevice == nullptr){
            m_modbusDevice = new QModbusTcpClient(this);
        } else {
            QModbusTcpClient* temp =dynamic_cast<QModbusTcpClient*>(m_modbusDevice);
            if(temp == nullptr){
                delete m_modbusDevice;
                m_modbusDevice = new QModbusTcpClient(this);
            }
        }

        m_modbusDevice = new QModbusTcpClient(this);
        m_modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, g_serialSetting.url);
        m_modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, g_serialSetting.port);
    }
    m_modbusDevice->setTimeout(g_serialSetting.responseTime);
    m_modbusDevice->setNumberOfRetries(g_serialSetting.numberOfRetries);

    if(m_modbusDevice->connectDevice()){
        ui->pushButton_start->setStyleSheet("background-color:green");
    } else {
        ui->pushButton_start->setStyleSheet("background-color:red");
    }

    /* set modbus param */
    m_modbusRequests = std::bind(&MainWindow::_ModbusRequests, this,g_modbusSetting.registerType
                                    , g_modbusSetting.readStartAddr
                                    , g_modbusSetting.readValueCount
                                    , g_modbusSetting.serverAddr);
    if(QModbusDataUnit::RegisterType::Coils == g_modbusSetting.registerType
            || QModbusDataUnit::RegisterType::DiscreteInputs == g_modbusSetting.registerType){
        u_axisY->setRange(0,2);
        u_axisX->setRange(0,10);
    } else {
        u_axisY->setRange(0,10);
        u_axisX->setRange(0,10);
        u_axisX_x = 0;
        u_lineSeries->clear();
    }
}

void MainWindow::_ModbusRequests(QModbusDataUnit::RegisterType regType, int newStartAddress, quint16 newValueCount,int serverAddress)
{
    if(!m_modbusDevice)
        return;
    if(QModbusDevice::State::UnconnectedState == m_modbusDevice->state())
        return;

    QModbusReply* reply = m_modbusDevice->sendReadRequest(
                QModbusDataUnit(regType,newStartAddress,newValueCount)
                , serverAddress);
    if (!reply->isFinished())
        connect(reply, &QModbusReply::finished, this, &MainWindow::_onModbusReadReady);
    else
        delete reply; // broadcast replies return immediately
}

void MainWindow::_onModbusReadReady()
{
    QModbusReply* reply = dynamic_cast<QModbusReply*>(sender());

    if (reply->error() == QModbusDevice::NoError)
    {
        QModbusDataUnit dataUnit = reply->result();
        if(!dataUnit.isValid()){
            disconnect(reply, &QModbusReply::finished, nullptr, nullptr);
            if(QModbusDevice::State::ConnectedState == m_modbusDevice->state())
                QTimer::singleShot(1000, m_modbusRequests);
            return;
        }

        qreal value = 0;

        /*
         * modbus slave模拟器来的数据，高位在低字节，
         * x86的小端模式，低地址应该是低位。
         *
         * 如果发送来的数据是signal，字节顺序是A B高位在前
         * 需要的格式是BA
         * 自动处理结果也是BA
         *
         * 如果是long，发数据为AB CD
         * 需要的格式是 D C B A
         * 程序自动处理为 B A, D C
        */
        if(QModbusDataUnit::RegisterType::Coils == dataUnit.registerType()
            || QModbusDataUnit::RegisterType::DiscreteInputs == dataUnit.registerType())
        {
            value = dataUnit.value(0);
        }
        else
        {
            if(g_modbusSetting.readType == ModbusSetting::Signed){
                value = dataUnit.value(0);
            }
            else if(g_modbusSetting.readType == ModbusSetting::Unsidned){
                value = dataUnit.value(0);
            }
            else if(g_modbusSetting.readType == ModbusSetting::Long){
                value = (qint32)dataUnit.value(1) | (qint32)dataUnit.value(0)<<16;
            }
            else if(g_modbusSetting.readType == ModbusSetting::Float){
                qint32 tV = (qint32)dataUnit.value(1) | (qint32)dataUnit.value(0)<<16;
                value = *( (float*)(&tV) );
            }
            else if(g_modbusSetting.readType == ModbusSetting::Double){
                qint64 tV = (qint64)dataUnit.value(3) | (qint64)dataUnit.value(2)<<16
                                | (qint64)dataUnit.value(1)<<32 | (qint64)dataUnit.value(0)<<48;
                value = *( (double*)(&tV) );
            }
            else{
                value = dataUnit.value(0);
            }
        }

        qDebug()<<"dataUnit.value:"<<value;
        u_lineSeries->append(u_axisX_x, value);

        if(value>u_axisY->max())
            u_axisY->setRange(0, dataUnit.value(0)+1);
        if(value<u_axisY->min())
            u_axisY->setRange(value-1, u_axisY->max());

        u_axisX_x+=1;
        if(u_axisX_x>10)
            u_axisX->setRange(u_axisX_x-9, u_axisX_x);
    }

    disconnect(reply, &QModbusReply::finished, nullptr, nullptr);
    if(QModbusDevice::State::ConnectedState == m_modbusDevice->state())
        QTimer::singleShot(1000, m_modbusRequests);
}
